﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;


namespace network
{
    public class Node  // Node information class
    {
        public int ID;
        public IPEndPoint endPoint;

        public Node(int id, IPEndPoint EP)
        {
            this.ID = id;
            this.endPoint = EP;
        }
    }

    public class ElectionInfo // public information about the bully alorithm 
    {
        public readonly int myID;
        public Node leader;
        public volatile bool electionRunning;

        public delegate void SetLeaderHandler(ElectionInfo electionInfo, EventArgs args);
        public event SetLeaderHandler setLeaderHandler;
        
        public ElectionInfo()
        {
            this.electionRunning = false;
            this.myID = new Random().Next(0, 5000000);
            this.leader = new Node(-1, new IPEndPoint(IPAddress.Broadcast, 0));
        }
        public void setLeader(int id, IPEndPoint ep)
        {
            if (this.setLeaderHandler != null && id != this.myID)
            {
                this.setLeaderHandler(this, null);
            }

            this.electionRunning = false;
            this.leader = new Node(id, ep);
        }
        public void beginElection()
        {
            this.electionRunning = true;
        }
    }
    class FeedbackData  // information for assincronous UDP feedback communication
    {
        public IPEndPoint ep;
        public byte[] rcvData;
        public FeedbackData(IPEndPoint endpoint)
        {
            this.ep = endpoint;
        }
    }


    public struct MsgElectData  // parse structure for election messages
    {
        public string msgType;
        public int senderID;
    }

    public enum MsgType
    {
        FLAVOR_CHANGED, START_VM, STOP_VM, SAVE_VM
    }

    public class MessageArgs : EventArgs       // <TODO> modify to accept all kind of messages
    {
        public readonly MsgType messageType;
        public readonly List<string> messageArgsExtra = null;

        public MessageArgs(byte[] msg)
        {
            ASCIIEncoding encoder = new ASCIIEncoding();
            List<string> splitted = new List<string>(encoder.GetString(msg).Split(' '));

            this.messageType = (MsgType)Int32.Parse(splitted[0]);
            this.messageArgsExtra = splitted.GetRange(1, splitted.Count - 1);

        }
    }



    // Excepions
    public class GelatineNetworkException : SocketException
    {
    }

    public class UnexpectedMsg : GelatineNetworkException
    {
        private ASCIIEncoding encoder;

        public MsgElectData msgData;
        public string rcvMsg;

        public UnexpectedMsg(MsgElectData receivedMsg)
        {
            this.msgData = receivedMsg;
            this.rcvMsg = this.msgData.msgType;
        }
        public UnexpectedMsg(byte[] receivedData)
        {
            this.encoder = new ASCIIEncoding();
            this.rcvMsg = encoder.GetString(receivedData);
        }
    }
    public class AckTimeout : GelatineNetworkException
    {
    }
    public class NoInterface : GelatineNetworkException
    {
    }



    public static class GenericMethods
    {
        public static bool equalMsg(byte[] s1, byte[] s2)
        {
            ASCIIEncoding encoder = new ASCIIEncoding();
            return equalMsg(encoder.GetString(s1), encoder.GetString(s2));
        }
        public static bool equalMsg(string s1, byte[] s2)
        {
            ASCIIEncoding encoder = new ASCIIEncoding();
            return equalMsg(s1, encoder.GetString(s2));
        }
        public static bool equalMsg(string s1, string s2)
        {
            if (String.Compare(s1, s2) == 0)
                return true;
            else
                return false;
        }
        public static MsgElectData parseElectionMsg(byte[] msg)
        {
            ASCIIEncoding encoder = new ASCIIEncoding();
            MsgElectData returnStruct;
            string[] splitted = encoder.GetString(msg).Split(' ');
            returnStruct.msgType = splitted[0];
            returnStruct.senderID = Int32.Parse(splitted[1]);
            return returnStruct;
        }
    }
}